#include "XpmTermBlock.h"
#include <algorithm>

namespace xpm {
	RemainRangePair XpmTermBlock::RemoveCharsInPosRange(int start, int charsRemoved) {
		// need to adjust the position
		if( start < _pos) {
			// adjust the number of chars removed
			charsRemoved = start + charsRemoved - _pos;
			// move the block to the start
			_pos = start;			
		}

		RemainRangePair pair;
		int end = start + charsRemoved;
		/*if( start <= _pos) {
			_pos = start + charsRemoved;
		}*/
		//2. adjust the offset in the block
		start -= _pos;
		end -= _pos;
		//3. only one iteraty can solve the problem!
		for(TermIter it = _terms.begin(); it != _terms.end(); ) {
			//find start term and end term
			// case 1
			if( end <= it->posInBlock()) {
				// need to revise
				it->setPosInBlock(it->posInBlock() - charsRemoved);
				++it;
			}
			// case 3.3
			else if ( start >= it->end()) {
				++it;
			}
			// case 2, 3.1, 3.2
			else {
				// case 3.2, 3.2
				if (start > it->posInBlock()) {
					RemainRange left(_pos +  it->posInBlock(), start - it->posInBlock());
				    pair.first = left;
				}
				// case 2
				if (end < it->end()) {
					RemainRange right(_pos + start, it->end() - end);
				    pair.second = right;
				}
				// need to erase
				it = _terms.erase(it);
			}
		}
		return pair;
	}
	void XpmTermBlock::RemoveSomethingBefore(int startpos, int charsRemoved) {
		// need to adjust the position
		if( startpos < _pos) {
			// adjust the number of chars removed
			charsRemoved = startpos + charsRemoved - _pos;
			// move the block to the start
			_pos = startpos;			
		}

		int end = startpos + charsRemoved;
		/*if( start <= _pos) {
			_pos = start + charsRemoved;
		}*/
		//2. adjust the offset in the block
		startpos -= _pos;
		end -= _pos;
		//3. only one iteraty can solve the problem!
		for(TermIter it = _terms.begin(); it != _terms.end(); ++it ) {
			//find start term and end term
			// case 1
			if( end <= it->posInBlock()) {
				// need to revise
				it->setPosInBlock(it->posInBlock() - charsRemoved);
			}
		}
	}
	RemainRange XpmTermBlock::RemoveMap(TermIter& termIter) {
		RemainRange remain;
		if(termIter != _terms.end()) {
			remain.setPosition(_pos + termIter->posInBlock());
			remain.setLength(termIter->length());
		    _terms.erase(termIter);
		}
		return remain;
	}
	RemainRangePair XpmTermBlock::AddCharsInPosRange(int start, int charsAdded) {
		RemainRangePair pair;
		TermIter currentIt = _terms.end();
		start -= _pos;
		int end = start + charsAdded;
		int bshouldRemove = false;
		for(TermIter it = _terms.begin(); it != _terms.end();) {
			// case 3
			if ( start >= it->end()) {
				++it;
			}
			// case 1
			else if ( start <= it->posInBlock()) {
				it->setPosInBlock( it->posInBlock() + charsAdded);
				++it;
			}			
			// case 2
			else {
				RemainRange left(_pos + it->posInBlock(), it->length() + charsAdded);
				pair.first = left;
				it = _terms.erase(it);
			}
		}		
		return pair;
	}
	void XpmTermBlock::AddSomethingBefore(int startpos, int charsAdded) {
		startpos -= _pos;
		int end = startpos + charsAdded;
		int bshouldRemove = false;
		for(TermIter it = _terms.begin(); it != _terms.end(); ++it) {
			// case 1
			if ( startpos <= it->posInBlock()) {
				it->setPosInBlock( it->posInBlock() + charsAdded);
			}	
		}
	}

	TermIter XpmTermBlock::GetTermIterByPos(int pos) {
		pos -= _pos;
		for(TermIter it = _terms.begin(); it  != _terms.end(); ++it ) {
			if(pos >= it->posInBlock() && pos < (it->posInBlock() + it->length()))
				return it;
		}
		return _terms.end();
	}
	void XpmTermBlock::AppendTermRange(int startpos, wstring text, conex::Term* term) {
		if ( term != 0) {
			TermRange range(startpos, text, term);
			_terms.push_back(range);
		}
	}
	// need more debug, there are some errors
	// 1. add maps for the same start position
	RemainRangePair XpmTermBlock::AddMap(int startpos, wstring text, conex::Term* term) {
		RemainRangePair pair;
		//there are three conditions
		//1. find the before iterator		
		int length = text.length();
		startpos -= _pos;
		int end = startpos + length;
		TermIter before = _terms.end();		
		TermIter current = _terms.end();
		bool bshouldRemove = false;
		for(TermIter it  = _terms.begin(); it != _terms.end(); ++it) {
			if( it->posInBlock() < startpos && it->end() > startpos) {
				RemainRange left(_pos + it->posInBlock(), _pos + startpos - it->posInBlock());
				RemainRange right(_pos + end, _pos + it->end() - startpos);
				pair.first = left;
				pair.second = right;
				bshouldRemove = true;
				current = it;
				before = it;
				if(before != _terms.end()) 
					++before;
			}else if(it->posInBlock() >= startpos) {
				if(before == _terms.end())
				    before = it;						
			}						
		}
		//2. find current term, we need to replace current one
		if(bshouldRemove && current != _terms.end()) {
			_terms.erase(current);
		}
		//3. insert current range
		if(term) {
			TermRange range(startpos, text, term);
			_terms.insert(before, range);
		}
		wcout << L"inserted for term :" << term->id()->word() << L" in position :" << startpos << L" and length: " << length << endl;
		return pair;
	}

	//precise find with seleciton range
	/*void XpmTermBlock::FindByRange(SelectionRange* range, TermIter &term) {
		term = _terms.end();
		for(TermIter it = _terms.begin(); it != _terms.end(); ++it) {
			if((it->posInBlock() + position()) == range->startpos && it->length() == range->text.length()) {
				term = it;
			}
		}
	}*/

	void XpmTermBlock::findTermRanges(int pos, int len, vector<TermRange>& trs) {
		if ( pos <= _pos ) {
			pos = 0;
			len = pos + len - _pos;
		} else
			pos -= _pos;
		for(TermIter it = _terms.begin(); it != _terms.end(); ++it) {
			if ( pos <= it->posInBlock() && (pos + len) >= it->end()) {
				TermRange tr(it->posInBlock() + _pos, it->text(), it->term());
				trs.push_back(tr);
			}				
		}
	}
}